<?php
/***********************************/
// World of Warcraft Armory SDK    //
// Licence: GNU GPLv3              //
// Author: Giacomo 'elegos' Furlan //
// File: wowasdk.achievements.php  //
/***********************************/

/**
  This class allows you to browse
  your character's achievements
  data from the Armory.
*/
class wowasdk_achievements {
	private $xmlsheet;
	private $region;
	private $char_url;
	private $categories;
	private $urls;
	
	/**
	  Achievement categories extractor, used to dynamically extract the category IDs.
	**/
	private function extractCategories() {
		if(isset($this->xmlsheet[0]->achievements->rootCategories->category)) {
			foreach($this->xmlsheet[0]->achievements->rootCategories->category as $category) {
				$name = (string)$category->attributes()->name;
				$id = (int)$category->attributes()->id;
				$this->categories[$name] = $id;
			}
			return true;
		}
		else return false;
	}
	
	/**
	  Achievement category XML initialiser, used to dynamically set and download it.
	*/
	private function loadCategory($id) {
		if(isset($this->xmlsheet[$id])) return;
		$r_string = $this->urls["base_achievement_category_url"]."$id";
		$fileurl = $this->urls["fileurl"];
			
		$file = "$fileurl$id.xml";
		downloadFileViaCurl($r_string,$file,86400,$this->force_cache);
			
		$this->xmlsheet[$id] = simplexml_load_file("$fileurl$id.xml");
	}
	
	/**
	  Constructor of the class.
	  Returns false if some files returned an error.
	  @param $region EU or US
	  @param $server The server's name
	  @param $cname The character's name
	  @param $force_cache TRUE: new data will be downloaded; FALSE: new data will be downloaded only if the cache one is outdated (3 days)
	*/
	function __construct($region,$server,$cname, $force_cache = false) {
		$return = true;
		$server = explode(" ",$server);
		for($i = 0; $i < count($server); $i++) {
			$server[$i] = ucfirst(strtolower($server[$i]));
		}
		$server = implode(" ",$server);
		$server_plus = str_replace(" ","+",$server);
		$fileurl = "characters/$region/$server/$cname/achievements/";
		$this->urls = array();
		$this->urls["fileurl"] = $fileurl;
		$this->force_cache = $force_cache;
		
		$this->region = $region;
		
		@mkdir($fileurl,0777,true);

		switch($region) {
			case EU:
				$char_url = "http://eu.wowarmory.com/character-achievements.xml?";
				break;
			case US:
				$char_url = "http://www.wowarmory.com/character-achievements.xml?";
				break;
			default:
				die("No valid region selected.\n");
		}
		
		$r_string = $char_url."r=$server_plus&cn=$cname";
		$this->urls["base_achievement_category_url"] = $r_string."&c=";
		$file = $fileurl."0.xml";
		// daily update
		downloadFileViaCurl($r_string,$file,86400,$force_cache);

		$this->xmlsheet[0] = simplexml_load_file($fileurl."0.xml");
		
		if(!$this->extractCategories())
			$return = false;
		
		return $return;
	}
	
	/**
	  (Array) Last 4 achievements made by the character.
	  return[id][dateCompleted/desc/icon/points/title]
	*/
	function latestAchievements() {
		foreach($this->xmlsheet[0]->achievements->summary->achievement as $ach) {
			$result[(int)$ach->attributes()->id] = array(
					"dateCompleted" => (string)$ach->attributes()->dateCompleted,
					"desc" => (string)$ach->attributes()->desc,
					"icon" => (string)$ach->attributes()->icon,
					"points" => (int)$ach->attributes()->points,
					"title"	=> (string)$ach->attributes()->title,
				);
		}
		return $result;
	}
	
	/**
	  (Array) List of achievements of a certain category by category id. (false) if the category doesn't exist.
	  return[ach_id][completed/dateCompleted/desc/icon/points/title/criteria] -> (string) criteria[ach_id] = name
	  @param $id the achievements category id
	*/
	function getAchievementsByCategoryId($id) {
		$this->loadCategory($id);
		if(count($this->xmlsheet[$id]->category->achievement) > 0) {
			foreach($this->xmlsheet[$id]->category->achievement as $ach) {
				$completed = false;
				if($ach->attributes()->dateCompleted) $completed = true;
				$result[(int)$ach->attributes()->id] = array(
						"completed"		=> $completed,
						"dateCompleted" => (string)$ach->attributes()->dateCompleted,
						"desc"			=> (string)$ach->attributes()->desc,
						"icon"			=> (string)$ach->attributes()->icon,
						"points"		=> (int)$ach->attributes()->points,
						"title"			=> (string)$ach->attributes()->title,
					);
				if(count($ach->criteria) > 0) {
					foreach($ach->criteria as $criteria) {
						if(!$completed && !isset($criteria->attributes()->date)) continue;
						$result[(int)$ach->attributes()->id]["criteria"][(int)$criteria->attributes()->id] = (string)$criteria->attributes()->name;
					}
				}
			}
		}
		if(count($this->xmlsheet[$id]->category->category) > 0) {
			foreach($this->xmlsheet[$id]->category->category as $category) {
				if(count($category->achievement) > 0) {
					foreach($category->achievement as $ach) {
						$completed = false;
						if($ach->attributes()->dateCompleted) $completed = true;
						$result[(int)$ach->attributes()->id] = array(
								"completed"		=> $completed,
								"dateCompleted" => (string)$ach->attributes()->dateCompleted,
								"desc" => (string)$ach->attributes()->desc,
								"icon" => (string)$ach->attributes()->icon,
								"points" => (int)$ach->attributes()->points,
								"title"	=> (string)$ach->attributes()->title,
							);
						if(count($ach->criteria) > 0) {
							foreach($ach->criteria as $criteria) {
								if(!$completed && !isset($criteria->attributes()->date)) continue;
								$result[(int)$ach->attributes()->id]["criteria"][(int)$criteria->attributes()->id] = (string)$criteria->attributes()->name;
							}
						}
					}
				}
			}
		}
		
		if(!isset($result)) return false;
		return $result;
	}
	
	/**
	  (Array) List of achievements of a certain category by category name, implements getAchievementsByCategoryId. (false) if the category doesn't exist.
	  return[ach_id][dateCompleted/desc/icon/points/title/criteria] -> (string) criteria[ach_id] = name
	  @param $name the achievements category name
	*/
	function getAchievementsByCategoryName($name) {
		$id = $this->categories[$name];
		if($id == null) return false;
		return $this->getAchievementsByCategoryId($id);
	}
	
	/**
	  (Integer) Achievement Points earned by the character.
	*/
	function getAchievementPoints() {
		return (int)$this->xmlsheet[0]->achievements->summary->c->attributes()->points;
	}
	
	/**
	  (Integer) Number of earned achievements.
	*/
	function getAchievementsEarnedNumber() {
		return (int)$this->xmlsheet[0]->achievements->summary->c->attributes()->earned;
	}
	
	/**
	  (Integer) Total number of achievements.
	*/
	function getAchievementsTotalNumber() {
		return (int)$this->xmlsheet[0]->achievements->summary->c->attributes()->total;
	}
	
	/**
	  (Boolean) Search in the achievements done by the character for a certain one.
	  TRUE if it's been done, FALSE otherwise.
	  @param $achievement the achievement ID or title
	  @param $category the category ID or name in which to search
	*/
	function isAchievementDone($achievement,$category) {
		if(is_string($category))
			$category = $this->categories[$category];
		$this->loadCategory($category);

		// the category doesn't exist, return false
		if(!isset($this->xmlsheet[$category]))
			return false;
		
		$catArray = $this->getAchievementsByCategoryId($category);
		
		if(is_string($achievement)) {
			foreach($catArray as $ach)
				if($ach["title"] == $achievement) return $ach["completed"];
		}
		else if(is_int($achievement)) {
			return $catArray[$achievement]["completed"];
		}

		// if not string or integer, or it was not found, return false
		return false;
	}
	
	/**
	  (Boolean) Search in the achievements done by the character for a certain criteria.
	  TRUE if it's been done, FALSE otherwhise.
	  @param $achievement the achievement ID or title
	  @param $criteria the criteria ID or title to search for
	  @param $category the category ID or name in which to search
	*/
	function isAchievementCriteriaDone($achievement,$criteria,$category) {
		if(is_string($category))
			$category = $this->categories[$category];
		$this->loadCategory($category);
		
		if(!isset($this->xmlsheet[$category]))
			return false;

		$catArray = $this->getAchievementsByCategoryId($category);
		
		if(is_string($achievement)) {
			foreach($catArray as $ach) {
				if($ach["title"] == $achievement) {
					$ach2criteria = $ach;
					break;
				}
			}
		} else {
			$ach2criteria = $catArray[$achievement];
		}
		
		if(is_array($ach2criteria) && isset($ach2criteria["criteria"])) {
			if(is_string($criteria)) {
				foreach($ach2criteria["criteria"] as $id => $name) {
					if($name == $criteria) return true;
				}
			} else {
				return isset($ach2criteria["criteria"][$criteria]);
			}
		}
		
		return false;
	}
}

?>
